%% User interface server
-module(ui).
-behaviour(gen_server).

%% gen_server exports
-export([init/1, handle_call/3, handle_info/2]).
%% UI functions
-export([start_link/1, set_size/2, exit/0, set_pixel/1]).

%% Initialize the UI server
%%
%%  Arguments:
%%      Server = {Host, Port}
%%          Host = term()
%%          Port = int()
init({Host, Port}) ->
    % Connect to the UI server
    State = case gen_tcp:connect(Host, Port, [binary]) of
        {ok, Socket} -> Socket;
        {error, Reason} ->
            error_logger:info_msg("UI: error connecting to host: ~p. Continuing... ~n", [Reason]),
            no_ui
    end,
    {ok, State}.

%% Catch-all handler in case no UI is connected
handle_call(_Arg, _From, no_ui) ->
    {reply, ok, no_ui};
%% UI command handler
handle_call({cmd, Name, Params}, _From, Socket) ->
    send_message(Socket, Name, Params),
    {reply, ok, Socket};
%% set_pixel handler
handle_call({set_pixel, {X, Y, Color}}, _From, Socket) ->
    {R, G, B} = color:split(color:clip(Color)),
    send_message(Socket, "px", [X, Y, round(R*255), round(G*255), round(B*255)]),
    {reply, ok, Socket}.

%% Exit when the UI connection closes
handle_info({tcp_closed, _Port}, _Socket) ->
    error_logger:info_msg("UI: host went away~n", []),
    {noreply, no_ui};
handle_info(Msg, State) ->
    io:format("UI got info: ~p~n", [Msg]),
    {noreply, State}.

%% Start the ui server
%%
%%  Types:
%%      Server = {Host, Port}
%%          Host = term()
%%          Port = int()
%%      Result = {ok,Pid} | ignore | {error,Error}
%%          Pid = pid()
%%          Error = {already_started,Pid} | term()
%%
start_link(Server) ->
    gen_server:start_link({global, ui_server}, ui, Server, []).

%% Send a set the size of the rendering
set_size(Width, Height) ->
    gen_server:call({global, ui_server}, {cmd, "set_size", [Width, Height]}).

%% Exit the UI
exit() ->
    gen_server:call({global, ui_server}, {cmd, "exit", []}).

%% Set a pixel on the rendered image
set_pixel(Pixel) ->
    gen_server:call({global, ui_server}, {set_pixel, Pixel}).

%% Send a message to the UI
send_message(Socket, Cmd, List) -> 
	gen_tcp:send(Socket, term_to_binary([Cmd|List])).